#include "bsp_key.h"
#include <stdio.h>
#include <stdarg.h>
#include "gpio.h"
#include "FreeRTOS.h"
#include "cmsis_os.h"
#include "usart.h"
#include "queue.h"
#include "task.h"
#include "ITM.h"

// #include "bsp_uart.h"

QueueHandle_t gLEDQueueHandle = 0;   // 按键事件队列句柄
QueueHandle_t gLEDZeroCopyQueueHandle = 0;   // 按键事件队列句柄
osSemaphoreId gSWSemHandle = 0;      // 按键中断信号量句柄
extern osMutexId usartMutexHandle;   // 串口互斥锁句柄
uint32_t gtime_cap; //捕获执行时间
uint32_t gtime_cap_zero_copy; //捕获执行时间
int gitCnt = 0;
float gtime_cap_us;
float gtime_cap_zero_copy_us;
int uart_printf(const char *fmt, ...);

typedef struct sw_event
{
    uint8_t id;     // 按键ID
    uint8_t event;  // 按键事件
} sw_event_t;
typedef struct led_event
{
    uint16_t id;      // LED ID
    uint16_t repeat;  // LED 重复次数
    uint32_t time_on;
    uint32_t time_off;
    int arr[100];
}led_event_t;

enum sw_id
{
    SW1_ID = 0,
};

// 调试打印
#define debugPrint(str, ...) uart_printf(str, ##__VA_ARGS__)
// 按键输入电平读取
#define Bsp_Key_ReadPin(Port, Pin) HAL_GPIO_ReadPin(Port, Pin)
/* [1] 创建按键对象 */
iSW_t hisw1[BSP_KEY_NUM] = {0};
/* [2] 实现按键电平读取接口 */
void bsp_key_input_read(uint8_t offset, uint8_t *results, uint16_t num)
{
    if (results == NULL || BSP_KEY_NUM - offset < num)
    {
        debugPrint("Error: bsp_key_input_read\n");
        return ;
    }
    uint16_t i = 0;
    switch (offset) // 偏移值用来方便读取单个按键
    {
    case 0:
        if (num > i)
            results[i++] = Bsp_Key_ReadPin(KEY0_GPIO_Port, KEY0_Pin);
        else break;
    default:
        break;
    }
}

/* ---[3] 初始按键并配置功能--- */
void bsp_key_init(void)
{
    // 初始化按键 设置触发为低电平，消抖时间为10ms
    iSW_Init(hisw1, BSP_KEY_NUM, iSW_TRIGGER_LEVEL_LOW, 10);
    // 设置按键3为模式2，长按时间为2s，短按时间为20ms 触发方式为松开触发，双击时间为40ms~200ms
    iSW_Set_Mode2(&hisw1[0], 2000, 20, iSW_TRIGGER_WAY_RELEASE);    
    iSW_Set_Double_Click(&hisw1[0], 40, 200);

}

void bsp_queue_init(void)
{
    gLEDQueueHandle = xQueueGenericCreate(5, sizeof(led_event_t) , 0);
    gLEDZeroCopyQueueHandle = xQueueGenericCreate(1, sizeof(led_event_t*) , 0);
    gSWSemHandle = xSemaphoreCreateBinary();
}

static led_event_t ledevent; // 零拷贝数据需要单独开辟内存空间
int led_blink(uint16_t id, uint16_t repeat, uint32_t time_on, uint32_t time_off)
{
    memcpy(&ledevent, &(led_event_t){id, repeat, time_on, time_off}, sizeof(led_event_t));
    led_event_t *pledevent = &ledevent;
    /*---------------------- 发送测试 -----------------------*/
    gtime_cap = DWT_GetTicks(); // 获取当前时间ticks
    if (xQueueSend(gLEDQueueHandle, &ledevent, 0) != pdTRUE)
    {
        debugPrint("Error: xQueueSend\n");
        return -1;
    }
    gtime_cap_us = DWT_Time_Measure(&gtime_cap); // 测量时间结束
    gtime_cap_zero_copy = DWT_GetTicks(); // 获取当前时间ticks
    if (xQueueSend(gLEDZeroCopyQueueHandle, &pledevent, 0) != pdTRUE)
    {
        debugPrint("Error: xQueueSend\n");
        return -1;
    }
    gtime_cap_zero_copy_us = DWT_Time_Measure(&gtime_cap_zero_copy); // 测量时间结束
    debugPrint("send test >> LED time:%.2fus, LED zero copy time:%.2fus <<\n\r",
               gtime_cap_us, gtime_cap_zero_copy_us);
    /*---------------------- 接收测试 -----------------------*/
    gtime_cap = DWT_GetTicks(); // 获取当前时间ticks
    xQueueReceive(gLEDQueueHandle, &ledevent, 0);
    gtime_cap_us = DWT_Time_Measure(&gtime_cap); // 测量时间结束
    gtime_cap_zero_copy = DWT_GetTicks(); // 获取当前时间ticks
    xQueueReceive(gLEDZeroCopyQueueHandle, &ledevent, 0);
    gtime_cap_zero_copy_us = DWT_Time_Measure(&gtime_cap_zero_copy); // 测量时间结束
    debugPrint("receive test >> LED time:%.2fus, LED zero copy time:%.2fus <<\n\r",
               gtime_cap_us, gtime_cap_zero_copy_us);
    return 0;
}

static void SW_Handler(const struct sw_event *e)
{
    switch (e->id)
    {
    case SW1_ID:
        if (e->event & iSW_EVENT_PRESS)
        {
            debugPrint("KEY0 press start\n\r");
        }
        if (e->event & iSW_EVENT_SHORT)
        {
            debugPrint("KEY0 short press\n\r");
            // HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
            led_blink(0, 1, 900, 100);
        }
        if (e->event & iSW_EVENT_LONG)
        {
            debugPrint("KEY0 long press\n\r");
            led_blink(0, 3, 500, 500);
        }
        if (e->event & iSW_EVENT_DOUBLE_CLICK)
        {
            debugPrint("KEY0 double click\n\r");
        }
        if (e->event & iSW_EVENT_RELEASE)
        {
            debugPrint("KEY0 release\n\r");
        }
        break;
    default:
        break;
    }
}

void TaskInput(void const * argument)
{
    BaseType_t status;
    uint8_t key_input[BSP_KEY_NUM];
    uint32_t time_ms;
    struct sw_event swe = {0};
    bsp_key_init();
    while (0 == gSWSemHandle) osDelay(10);
    debugPrint("TaskInput start\n\r");
    while(1)
    {
        HAL_NVIC_EnableIRQ(KEY0_EXTI_IRQn); // 使能外部中断
        status = xSemaphoreTake(gSWSemHandle, portMAX_DELAY); // 等待按键事件
        if (pdTRUE == status)
        {
            // 打印测试信息
            // uint32_t time_cap = gtime_cap; // 获取发送队列时的时间
            // debugPrint("ISR time:%.2fus, ISR delay:%.2fus, it cnt:%d\n\r",
            //     swe.id, gtime_cap_us, DWT_Time_Measure(&time_cap), gitCnt);
            gitCnt = 0;
            osDelay(1);
            while (1)
            {
                /* [4] 在任务或定时器(1~20ms)中读取按键输入数据，并使用iSW_Scan来扫描输入数据 */
                bsp_key_input_read(0, key_input, BSP_KEY_NUM);
                uint32_t time_scan = HAL_GetTick() - time_ms; // 计算扫描间隔时间
                if (iSW_Scan(hisw1, key_input, BSP_KEY_NUM, time_scan))
                {
                    swe.event = iSW_EVENT_GET(&hisw1[0], iSW_EVENT_ALL);
                    if (swe.event)
                    {
                        SW_Handler(&swe);
                    }
                    iSW_Clear(&hisw1[0], BSP_KEY_NUM);
                }
                time_ms = HAL_GetTick(); // 获取当前时间
                // 检查是否有按键还需要继续扫描
                status = pdFALSE;
                for (size_t i = 0; i < BSP_KEY_NUM; i++)
                {
                    if (iSW_IS_PRESS(&hisw1[i]))
                    {
                        status = pdTRUE;
                    }
                }
                if (pdFALSE == status) break;
                osDelay(10);
            }
        }
    }
}


int LED_Handler(led_event_t *lede)
{
    if (lede->time_off == 0 || lede->time_on == 0)
    {
        debugPrint("Error: time_on or time_off is 0\n\r");
        return -1;
    }
    while (lede->repeat--)
    {
        HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
        osDelay(lede->time_on);
        HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET);
        osDelay(lede->time_off);
    }
    return 0;
}
void TaskLED(void const *argument)
{
    // BaseType_t status;
    // led_event_t lede;
    while (0 == gLEDQueueHandle) osDelay(10);
    debugPrint("TaskLED start\n\r");
    osDelay(1000);
    debugPrint("led_event_t size:%d, led_event_t* size:%d\n\r",
            sizeof(led_event_t), sizeof(led_event_t*));
    while (1)
    {
        osDelay(10);
        // status = xQueueReceive(gLEDQueueHandle, &lede, portMAX_DELAY);
        // if (pdTRUE == status)
        // {
        //     // 处理LED事件
        //     LED_Handler(&lede);
        // }
    }
}

char fmtbuf[256]; // 注意栈溢出
int uart_printf(const char *fmt, ...)
{
    int cnt;
    va_list args;
    va_start(args, fmt);
    cnt = vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, args);
    va_end(args);
    if (osMutexWait(usartMutexHandle, 1000) == osOK)
    {
        if (HAL_UART_Transmit(&huart1, (uint8_t *)fmtbuf, cnt, 1000) != HAL_OK)
        {
            cnt = -1;
        }
        osMutexRelease(usartMutexHandle);
    }
    else
    {
        cnt = -1;
    }
    return cnt;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    BaseType_t HigherPriorityTaskWoken = pdFALSE;
    
    if (GPIO_Pin == KEY0_Pin)
    {
        HAL_NVIC_DisableIRQ(KEY0_EXTI_IRQn); // 关掉外部中断，防止多次触发
        xSemaphoreGiveFromISR(gSWSemHandle, &HigherPriorityTaskWoken);
        gitCnt++; // 按键中断次数
    }
    
    portYIELD_FROM_ISR(HigherPriorityTaskWoken);
}

